package gbench.appdemo.priceline.app;

import static gbench.common.tree.LittleTree.MFT;
import static gbench.common.tree.LittleTree.IRecord.REC;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;

import gbench.appdemo.priceline.calendar.TradingCalendar;
import gbench.appdemo.priceline.indicator.IPriceIndicator;
import gbench.appdemo.priceline.indicator.OHLC;
import gbench.appdemo.priceline.indicator.OhlcIndicatorEvaluator;
import gbench.appdemo.priceline.model.IDispatcher;
import gbench.appdemo.priceline.model.IRedisClient;
import gbench.appdemo.priceline.model.PeriodPriceLineModel;
import gbench.common.tree.LittleTree.IRecord;

/**
 * 
 * @author gbench
 *
 * @param <T>
 */
public class KLineModel<T extends IPriceIndicator> extends PeriodPriceLineModel<T>{

    /**
     * 
     * @param ticker
     * @param auto_create
     * @param periods
     */
    public KLineModel(String ticker, boolean auto_create, Number... periods) {
        super(ticker, auto_create, periods);
    }
    
    /**
     * redis_key 函数默认为：(key,period)->MFT("{0}-{1,number,#}",key,period) <br>
     * -----------------------------------------------------------------------
     * kline model 的闯将 <br>
     * redis_data redis 数据库缓存 <br>
     * ticker <br>
     * auto_create <br>
     * periods <br>
     * callback <br>
     * inner_callback <br>
     * @return KLineModel
     */
    @SuppressWarnings("unchecked")
    public static  KLineModel<OHLC> newInstance(final IRecord param) {
        final var jdbc = param.asMap("jdbc");
        final var ticker = param.str("ticker");
        final var auto_create= param.bool("auto_create",true);
        final var periods = param.aa("periods", Number.class);
        final var redisData = (ConcurrentHashMap<String,List<IRecord>>)param.get("redis_data");
        final var calendar = TradingCalendar.parse("trading.sql").get("DEFAULT");
        final var klineModel = new KLineModel<OHLC>(ticker, auto_create,periods);
        final BiFunction<String,Long,String> redis_key = (key,period)->MFT("{0}-{1,number,#}",key,period);
        final var inner_callback = (BiConsumer<PeriodPriceLineModel<OHLC>.PeriodPriceLineProcessor,OHLC>)
            param.get("inner_callback",(BiConsumer<PeriodPriceLineModel<OHLC>.PeriodPriceLineProcessor,OHLC>) (p,ohlc)->{});// 内层callback
        final var callback = (BiConsumer<PeriodPriceLineModel<OHLC>.PeriodPriceLineProcessor,OHLC>) (p,ohlc) -> {
            redisData.compute(redis_key.apply(ticker, p.getPeriod()), (k,v)->{
                if(v==null)v=new LinkedList<IRecord>();
                v.add(IRecord.OBJ2REC(ohlc));
                inner_callback.accept(p, ohlc);
                return v;
            });// compute
        }; // callback
        
        // 结构初始化
        klineModel.initialize(REC(
            "jdbc",jdbc, // jdbc 数据库配置
            "dispatcher", (IDispatcher) rec -> calendar.getIndex(rec.date("time"), rec.lng("period")),
            "evaluator", new OhlcIndicatorEvaluator(),// OHLC的指标计算。
            "rclient", (IRedisClient) (key, period, initiator) -> redisData.compute(redis_key.apply(key, period), 
                    (k,v)->v==null?initiator.get():v), // 开启redis缓存
            "sync_write", false, // 异步写入
            "callback", param.get("callback",callback)
        ));
        
        return klineModel;
    }

}
